package com.bjpowernode.shop.log.aop;

import com.alibaba.fastjson.JSON;
import com.bjpowernode.shop.log.anno.Log;
import com.bjpowernode.shop.log.domain.SystemLog;
import com.bjpowernode.shop.log.domain.SystemUser;
import com.bjpowernode.shop.log.mapper.SystemLogMapper;
import com.bjpowernode.shop.log.mapper.SystemUserMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Configuration
public class LogAop {

    @Resource
    private SystemLogMapper systemLogMapper;

    @Resource
    private SystemUserMapper systemUserMapper;

    @Around(value = "@annotation(com.bjpowernode.shop.log.anno.Log)")
    public Object logAround(ProceedingJoinPoint joinPoint) {

        // 获取目标方法的参数列表
        Object[] args = joinPoint.getArgs();

        try {
            // ==前置通知== 获取构造SystemLog对象所需信息

            // 获取用户名称
            String userId = SecurityContextHolder.getContext().getAuthentication().getName();
            SystemUser systemUser = systemUserMapper.selectById(userId);
            String username = systemUser.getUsername();

            // =获取注解的操作信息=
            // 获取目标方法的签名
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取目标方法对象
            Method method = signature.getMethod();
            // 获取注解,获取注解中的属性【操作信息】
            String operation = method.getAnnotation(Log.class).operation();

            // 获取目标方法全限定的方法名
            String className = method.getDeclaringClass().getName();
            String methodName = method.getName();
            String name = className + "." + methodName;

            // 目标方法执行前的机器时间
            long start = System.currentTimeMillis();

            // 获取目标方法执行时的ip地址
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            String ip = requestAttributes.getRequest().getRemoteAddr();

            // 执行目标方法
            Object proceed = joinPoint.proceed(args);

            // 目标方法执行结束时的机器时间
            long end = System.currentTimeMillis();
            long time = end - start;

            // ==后置通知==
            // 插入Log数据,新增日志记录
            systemLogMapper.insert(
                    SystemLog.builder()
                            .username(username)
                            // 操作信息
                            .operation(operation)
                            // 方法名
                            .method(name)
                            // 参数列表
                            .params(JSON.toJSONString(args))
                            // 方法执行时长
                            .time(time)
                            .ip(ip)
                            .createDate(new Date())
                            .build()
            );
            return proceed;
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}
